
#include "Producer.h"


Producer::Producer(ParamHandler *parParamHandler, bool complex) {
	paramHandler = parParamHandler;
	computeNameSet();
	computeStringValues();

	if (paramHandler->getEventInputDistribution() == UNIFORM)
		randomEventTypeGen = new UniformRandomGenerator(paramHandler->getSeed(), 0,paramHandler->getNumEventTypes()-1);
	else if (paramHandler->getEventInputDistribution() == NORMAL)
		randomEventTypeGen = new NormalRandomGenerator(paramHandler->getSeed(), 0,paramHandler->getNumEventTypes()-1, 1, 1);
	else if (paramHandler->getEventInputDistribution() == EXPONENTIAL)
		randomEventTypeGen = new ExponentialRandomGenerator(paramHandler->getSeed(), paramHandler->getNumEventTypes()-1, 1);

	set<int> alreadyUsed;
	for (int i=0; i<paramHandler->getNumEventTypes(); i++){
		cout << i << " --> ";
		int numAttr = paramHandler->getMinNumAttributes()+rand()%(1+paramHandler->getMaxNumAttributes()-paramHandler->getMinNumAttributes());
		std::vector<FieldDescrType*> vector;
		for (int j=0; j<numAttr; j++){
			FieldDescrType* fd = (FieldDescrType*)malloc(sizeof(FieldDescrType));
			int nameRand;
			do {
				nameRand = rand()%paramHandler->getNumNames();
			} while (alreadyUsed.find(nameRand) != alreadyUsed.end());
			alreadyUsed.insert(nameRand);
			for (int k=0; k<NAME_LEN-1; k++) {
				fd->name[k] = names[nameRand][k];
			}
			fd->name[NAME_LEN-1] = '\0';
			if (rand()%2==0){
				fd->type = INT;
				int value1 = paramHandler->getMinIntValue() + rand()%(1+paramHandler->getMaxIntValue()-paramHandler->getMinIntValue());
				int value2 = paramHandler->getMinIntValue() + rand()%(1+paramHandler->getMaxIntValue()-paramHandler->getMinIntValue());
				cout << "INT{" << value1 << ":" << value2 << "}, ";
				if (value1 < value2) {
					fd->generator = new NormalRandomGenerator(paramHandler->getSeed(), value1, value2, 1, 1);
				} else {
					fd->generator = new NormalRandomGenerator(paramHandler->getSeed(), value2, value1, 1, 1);
				}
			} else {
				fd->type = STRING;
				int value1 = rand()%(paramHandler->getNumStringValues());
				int value2 = rand()%(paramHandler->getNumStringValues());
				cout << "STRING{" << value1 << ":" << value2 << "}, ";
				if (value1 < value2) {
					fd->generator = new NormalRandomGenerator(paramHandler->getSeed(), value1, value2, 1, 1);
				} else {
					fd->generator = new NormalRandomGenerator(paramHandler->getSeed(), value2, value1, 1, 1);
				}
			}
			vector.push_back(fd);
		}
		cout << endl;
		pubDescrMap.insert(make_pair(i,vector));


//if (!complex){
		SubDescrType* sd = (SubDescrType*)malloc(sizeof(SubDescrType));
		int windowMax = rand()%paramHandler->getMaxWindowSize();
//		windowMax = paramHandler->getIncremento() * windowMax;

		if (paramHandler->getEventInputDistribution() == UNIFORM)
			sd->windowGenerator = new UniformRandomGenerator(paramHandler->getSeed(), 0,windowMax);
		else if (paramHandler->getEventInputDistribution() == NORMAL)
			sd->windowGenerator = new NormalRandomGenerator(paramHandler->getSeed(), 0,windowMax, paramHandler->getParWindowDistribution(), paramHandler->getIncremento());
		else if (paramHandler->getEventInputDistribution() == EXPONENTIAL)
			sd->windowGenerator = new ExponentialRandomGenerator(paramHandler->getSeed(), windowMax, paramHandler->getParWindowDistribution());

//		int max = 10*(paramHandler->getParLastProb()+0.1);
//		float p = (rand()%max)/10;
//		sd->occurrenceGenerator = new BernoulliRandomGenerator(paramHandler->getSeed(), p);
		sd->occurrenceGenerator = new BernoulliRandomGenerator(paramHandler->getSeed(), paramHandler->getParLastProb());
		subDescrMap.insert(make_pair(i,sd));
//}
	}
//if (!complex){
	if (paramHandler->getSubsInputDistribution() == UNIFORM)
		randomSubsTypeGen = new UniformRandomGenerator(paramHandler->getSeed(), 0,paramHandler->getNumEventTypes()-1);
	else if (paramHandler->getSubsInputDistribution() == NORMAL)
		randomSubsTypeGen = new NormalRandomGenerator(paramHandler->getSeed(), 0,paramHandler->getNumEventTypes()-1, 1, 1);
	else if (paramHandler->getSubsInputDistribution() == EXPONENTIAL)
		randomSubsTypeGen = new ExponentialRandomGenerator(paramHandler->getSeed(), paramHandler->getNumEventTypes()-1, 1);
//}
if (complex){
	complexRandomSubsTypeGen = new UniformRandomGenerator(paramHandler->getSeed(), 1000,1000+paramHandler->getNumRules()-1);
}
}

Producer::~Producer() {

}

void Producer::resetNames() {
	names.clear();
	computeNameSet();
}

void Producer::resetStringValues() {
	stringValues.clear();
	computeStringValues();
}

void Producer::computeNameSet() {
	for (int i=0; i<paramHandler->getNumNames(); i++) {
		char *name = new char[NAME_LEN];
		for (int j=0; j<NAME_LEN-1; j++) {
			name[j] = 'a'+rand()%25;
		}
		name[NAME_LEN-1] = '\0';
		names.push_back(name);
		nameIds.insert(make_pair(name,names.size()-1));
	}
}

void Producer::computeStringValues() {
	// If all names are referred to integer values, there is no need to compute string values
	for (int i=0; i<paramHandler->getNumStringValues(); i++) {
		char *name = new char[STRING_VAL_LEN];
		for (int j=0; j<STRING_VAL_LEN-1; j++) {
			name[j] = 'a'+rand()%25;
		}
		name[STRING_VAL_LEN-1] = '\0';
		stringValues.push_back(name);
	}
}


PubPkt * Producer::createPubPkt() {

	PubPkt *pkt;
	boost::unordered_map<int,std::vector<FieldDescrType*> >::iterator itType = pubDescrMap.find(randomEventTypeGen->getNumber());
	if (itType != pubDescrMap.end()) {
		Attribute attributes[itType->second.size()];
		for (int i=0; i<itType->second.size(); i++){
			for (int k=0; k<NAME_LEN-1; k++) {
				attributes[i].name[k] = itType->second[i]->name[k];
			}
			attributes[i].name[NAME_LEN-1] = '\0';

			if (itType->second[i]->type == INT){
				attributes[i].type=INT;
				attributes[i].intVal = itType->second[i]->generator->getNumber();
			} else if (itType->second[i]->type == STRING){
				attributes[i].type=STRING;
				int index = itType->second[i]->generator->getNumber();
				for (int k=0; k<NAME_LEN-1; k++) {
					attributes[i].stringVal[k] = names[index][k];
				}
				attributes[i].stringVal[NAME_LEN-1] = '\0';
			}
		}
		pkt = new PubPkt(itType->first, attributes, itType->second.size());
		cout << "Created message: " << test::toString(pkt) << endl;
	}
	return pkt;
}


BackSubPkt * Producer::createBackSubPkt() {

	BackSubPkt *pkt;
	int type = randomSubsTypeGen->getNumber();
	boost::unordered_map<int,std::vector<FieldDescrType*> >::iterator itType = pubDescrMap.find(type);
	if (itType != pubDescrMap.end()) {
		Constraint constraints[itType->second.size()];
		for (int i=0; i<itType->second.size(); i++){
			for (int k=0; k<NAME_LEN-1; k++) {
				constraints[i].name[k] = itType->second[i]->name[k];
			}
			constraints[i].name[NAME_LEN-1] = '\0';

			if (itType->second[i]->type == INT){
				constraints[i].type=INT;
				constraints[i].intVal = itType->second[i]->generator->getNumber();
				constraints[i].op = getRandomOp(INT);
			} else if (itType->second[i]->type == STRING){
				constraints[i].type=STRING;
				int index = itType->second[i]->generator->getNumber();
				for (int k=0; k<NAME_LEN-1; k++) {
					constraints[i].stringVal[k] = names[index][k];
				}
				constraints[i].stringVal[NAME_LEN-1] = '\0';
				constraints[i].op = getRandomOp(STRING);
			}
		}

		boost::unordered_map<int,SubDescrType*>::iterator itSubType = subDescrMap.find(type);
		if (itSubType != subDescrMap.end()){
			float window = itSubType->second->windowGenerator->getNumber();
			int occurence = itSubType->second->occurrenceGenerator->getNumber();
			pkt = new BackSubPkt(type, constraints, itType->second.size(), window, (OccurrenceType)occurence);
			cout << "Created subscription: " << test::toString(pkt) << endl;
		}
	}
	return pkt;
}


Op Producer::getRandomOp(ValType type) {
	int r = rand()%100;
	int count = 0;
	if (type == INT) {
		count += paramHandler->getPercIntEq();
		if (r<count) return EQ;
		count += paramHandler->getPercIntLt();
		if (r<count) return LT;
		count += paramHandler->getPercIntGt();
		return GT;
	} else if (type == STRING) {
		return EQ;
	}
}



void Producer::createRulePkts(set<RulePkt *> &rules) {
	int numRules = paramHandler->getNumRules();

	for (int i=0; i<numRules; i++) {

		// Creates a new packet; resets count only if it is the first iteration in the cycle
		RulePkt *pkt = new RulePkt(i==0);

		int noType = addRootPredicate(pkt, i);

/*		int numSeqs = 1;
		for (int i=1; i<paramHandler->getNumRulePredicates(); i++) {
			if (addPredicate(pkt, (numSeqs<paramHandler->getMaxAutSeqs()))) numSeqs++;
		}
*/
		for (int j=1; j<paramHandler->getNumRulePredicates(); j++) {
			addPredicate(pkt, false, noType);
		}
		for (int j=0; j<paramHandler->getNumRuleNegations(); j++) {
			addNegation(pkt);
		}
		for (int j=0; j<paramHandler->getNumRuleParameters(); j++) {
			addParameter(pkt);
		}

		std::vector<FieldDescrType*> vector;


		CompositeEventTemplate *ceTemplate = new CompositeEventTemplate(1000+i);
	//	for (int j=0; j<pkt->getPredicatesNum(); j++){
	//	for (int j=0; j<1; j++){
		int j = rand()%pkt->getPredicatesNum();

			FieldDescrType* fd = (FieldDescrType*)malloc(sizeof(FieldDescrType));

			Predicate p = pkt->getPredicate(j);
			int j2;
			int count = 0;
			do {
				j2 = rand()%p.constraintsNum;
				count++;
			} while (p.constraints[j2].type == STRING && count<10);

			char *attrName = new char[NAME_LEN];
			for (int k=0; k<NAME_LEN-1; k++) {
					fd->name[k] = p.constraints[j2].name[k];
					attrName[k] = p.constraints[j2].name[k];
				}
			fd->name[NAME_LEN-1] = '\0';
			attrName[NAME_LEN-1] = '\0';
			fd->type = p.constraints[j2].type;
			OpTree *opTree = new OpTree(new RulePktValueReference(j, attrName), p.constraints[j2].type);
			ceTemplate->addAttribute(attrName, opTree);

			std::vector<FieldDescrType*> vec = pubDescrMap.find(p.eventType)->second;
			bool found = false;
			for (int z=0; z<vec.size(); z++){
				cout << "cerco: " << p.constraints[j2].name << " trovo: " << vec.at(z)->name << endl;
				if (0==strcmp(p.constraints[j2].name, vec.at(z)->name)){
					fd->generator = vec.at(z)->generator;
					found = true;
					break;
				}
			}
			if (!found) cout << "ERRORE" << endl;
			vector.push_back(fd);
	//	}
		pkt->setCompositeEventTemplate(ceTemplate);
		rules.insert(pkt);

		complexPubDescrMap.insert(make_pair(1000+i, vector));
		cout << "Created rule: " << test::toString(pkt) << endl;


		SubDescrType* sd = (SubDescrType*)malloc(sizeof(SubDescrType));
		int windowMax = rand()%paramHandler->getMaxWindowSize();

		if (paramHandler->getEventInputDistribution() == UNIFORM)
			sd->windowGenerator = new UniformRandomGenerator(paramHandler->getSeed(), 0,windowMax);
		else if (paramHandler->getEventInputDistribution() == NORMAL)
			sd->windowGenerator = new NormalRandomGenerator(paramHandler->getSeed(), 0,windowMax, paramHandler->getParWindowDistribution(), paramHandler->getIncremento());
		else if (paramHandler->getEventInputDistribution() == EXPONENTIAL)
			sd->windowGenerator = new ExponentialRandomGenerator(paramHandler->getSeed(), windowMax, 1);

		//float p = (rand()%10)/10;
		sd->occurrenceGenerator = new BernoulliRandomGenerator(paramHandler->getSeed(), paramHandler->getParLastProb());
		complexSubDescrMap.insert(make_pair(1000+i,sd));

	}
}


int Producer::addRootPredicate(RulePkt *pkt, int i) {

	int eventType = randomSubsTypeGen->getNumber();
	//int eventType = i;
	boost::unordered_map<int,std::vector<FieldDescrType*> >::iterator itType = pubDescrMap.find(eventType);
	if (itType != pubDescrMap.end()) {
	//	Constraint constraints[itType->second.size()];
	//	for (int i=0; i<itType->second.size(); i++){
		Constraint constraints[1];


		int indexConst = rand()%itType->second.size();
	/*	int indexConst;
		int count = 0;
		do {
			indexConst = rand()%itType->second.size();
			count++;
		} while (itType->second[indexConst]->type == STRING && count<10);
	*/

		for (int i=0; i<1; i++){
			for (int k=0; k<NAME_LEN-1; k++) {
				constraints[i].name[k] = itType->second[indexConst]->name[k];
			}
			constraints[i].name[NAME_LEN-1] = '\0';
			if (itType->second[indexConst]->type == INT){
				constraints[i].type=INT;
				constraints[i].intVal = itType->second[indexConst]->generator->getNumber();
				constraints[i].op = getRandomOp(INT);
			} else if (itType->second[indexConst]->type == STRING){
				constraints[i].type=STRING;
				int index = itType->second[indexConst]->generator->getNumber();
				for (int k=0; k<NAME_LEN-1; k++) {
					constraints[i].stringVal[k] = names[index][k];
				}
				constraints[i].stringVal[NAME_LEN-1] = '\0';
				constraints[i].op = getRandomOp(STRING);
			}
		}
		pkt->addRootPredicate(eventType, constraints, 1); //itType->second.size());
	}
	return eventType;

}


bool Producer::addPredicate(RulePkt *pkt, bool canSplit, int noType) {
	bool returnValue = false;
	int eventType;
	do {
		eventType = getRandomEventType();
	} while (eventType == noType);

	boost::unordered_map<int,std::vector<FieldDescrType*> >::iterator itType = pubDescrMap.find(eventType);
		if (itType != pubDescrMap.end()) {
		//	Constraint constraints[itType->second.size()];
		//	for (int i=0; i<itType->second.size(); i++){
			Constraint constraints[1];

			int indexConst = rand()%itType->second.size();
		/*	int indexConst;
			int count = 0;
			do {
				indexConst = rand()%itType->second.size();
				count++;
			} while (itType->second[indexConst]->type == STRING && count<10);
		*/
			for (int i=0; i<1; i++){
				for (int k=0; k<NAME_LEN-1; k++) {
					constraints[i].name[k] = itType->second[indexConst]->name[k];
				}
				constraints[i].name[NAME_LEN-1] = '\0';
				if (itType->second[indexConst]->type == INT){
					constraints[i].type=INT;
					constraints[i].intVal = itType->second[indexConst]->generator->getNumber();
					constraints[i].op = getRandomOp(INT);
				} else if (itType->second[indexConst]->type == STRING){
					constraints[i].type=STRING;
					int index = itType->second[indexConst]->generator->getNumber();
					for (int k=0; k<NAME_LEN-1; k++) {
						constraints[i].stringVal[k] = names[index][k];
					}
					constraints[i].stringVal[NAME_LEN-1] = '\0';
					constraints[i].op = getRandomOp(STRING);
				}
			}
/*
			int refersTo;
			if (canSplit) {
				refersTo = (rand()%pkt->getPredicatesNum());
				if (refersTo!=pkt->getPredicatesNum()-1) returnValue = true;
			} else {
				refersTo = pkt->getPredicatesNum()-1;
			}
*/
			int refersTo = pkt->getPredicatesNum()-1;
			TimeMs t = getWindow();
			CompKind kind = getCompKind();
			//pkt->addPredicate(eventType, constraints, itType->second.size(), refersTo, t, kind);
			pkt->addPredicate(eventType, constraints, 1, refersTo, t, kind);
			return returnValue;
		}
		return returnValue;
}


void Producer::addParameter(RulePkt *pkt) {
	bool neg = false;
	// Creates a parameter involving a negation (if at least a negation is defined)
	if ((rand()%100>50) && pkt->getNegationsNum()>0) neg = true;

	int index1, index2, constraintIndex1, constraintIndex2;
	char name1[2], name2[2];
	if (neg) {
		index1 = rand()%pkt->getPredicatesNum();
		index2 = rand()%pkt->getNegationsNum();
		constraintIndex2 = rand()%(pkt->getNegation(index2).constraintsNum);
		name2[0] = pkt->getNegation(index2).constraints[constraintIndex2].name[0];
	} else {
		index1 = (rand()%(pkt->getPredicatesNum()-1))+1;
		index2 = (rand()%index1);
		constraintIndex2 = rand()%(pkt->getPredicate(index2).constraintsNum);
		name2[0] = pkt->getPredicate(index2).constraints[constraintIndex2].name[0];
	}
	constraintIndex1 = rand()%(pkt->getPredicate(index1).constraintsNum);
	name1[0] = pkt->getPredicate(index1).constraints[constraintIndex1].name[0];
	name1[1] = '\0';
	name2[1] = '\0';
	if (neg) pkt->addParameterForNegation(index1, name1, index2, name2);
	else pkt->addParameterBetweenStates(index1, name1, index2, name2);
}


void Producer::addNegation(RulePkt *pkt) {
	int eventType = getRandomEventType();
	boost::unordered_map<int,std::vector<FieldDescrType*> >::iterator itType = pubDescrMap.find(eventType);
	if (itType != pubDescrMap.end()) {
		Constraint constraints[itType->second.size()];
		for (int i=0; i<itType->second.size(); i++){
			for (int k=0; k<NAME_LEN-1; k++) {
				constraints[i].name[k] = itType->second[i]->name[k];
			}
			constraints[i].name[NAME_LEN-1] = '\0';
			if (itType->second[i]->type == INT){
				constraints[i].type=INT;
				constraints[i].intVal = itType->second[i]->generator->getNumber();
				constraints[i].op = getRandomOp(INT);
			} else if (itType->second[i]->type == STRING){
				constraints[i].type=STRING;
				int index = itType->second[i]->generator->getNumber();
				for (int k=0; k<NAME_LEN-1; k++) {
					constraints[i].stringVal[k] = names[index][k];
				}
				constraints[i].stringVal[NAME_LEN-1] = '\0';
				constraints[i].op = getRandomOp(STRING);
			}
		}

		// Creates a negation between two states
		if ((rand()%100)<50) {
			int index1 = (rand()%(pkt->getPredicatesNum()-1))+1;
			int index2 = (rand()%index1);
			pkt->addNegationBetweenStates(eventType, constraints, itType->second.size(), index1, index2);
		}
		// Creates a time based negation
		else {
			int index2 = (rand()%pkt->getPredicatesNum());
			TimeMs win = getWindow();
			pkt->addTimeBasedNegation(eventType, constraints, itType->second.size(), index2, win);
		}
	}
}


int Producer::getRandomEventType() {
	return rand()%paramHandler->getNumEventTypes();
}


BackSubPkt * Producer::createComplexBackSubPkt() {

	BackSubPkt *pkt;
	int type = complexRandomSubsTypeGen->getNumber();
	cout << type << endl;
	boost::unordered_map<int,std::vector<FieldDescrType*> >::iterator itType = complexPubDescrMap.find(type);
	if (itType != complexPubDescrMap.end()) {
		Constraint constraints[itType->second.size()];
		for (int i=0; i<itType->second.size(); i++){
			for (int k=0; k<NAME_LEN-1; k++) {
				constraints[i].name[k] = itType->second[i]->name[k];
			}
			constraints[i].name[NAME_LEN-1] = '\0';

			if (itType->second[i]->type == INT){
				cout << "int" << endl;
				constraints[i].type=INT;
				constraints[i].intVal = itType->second[i]->generator->getNumber();
				constraints[i].op = getRandomOp(INT);
			} else if (itType->second[i]->type == STRING){
				cout << "string" << endl;
				constraints[i].type=STRING;

				int index = itType->second[i]->generator->getNumber();

				for (int k=0; k<NAME_LEN-1; k++) {
					constraints[i].stringVal[k] = names[index][k];
				}
				constraints[i].stringVal[NAME_LEN-1] = '\0';
				constraints[i].op = getRandomOp(STRING);
			}
		}

		boost::unordered_map<int,SubDescrType*>::iterator itSubType = complexSubDescrMap.find(type);
		if (itSubType != complexSubDescrMap.end()){
			float window = itSubType->second->windowGenerator->getNumber();
			int occurence = itSubType->second->occurrenceGenerator->getNumber();
			pkt = new BackSubPkt(type, constraints, itType->second.size(), window, (OccurrenceType)occurence);
			cout << "Created subscription: " << test::toString(pkt) << endl;
		}
	}
	return pkt;
}





TimeMs Producer::getWindow() {
	int winSize = (rand()%(paramHandler->getMaxWinSize()-paramHandler->getMinWinSize()))+paramHandler->getMinWinSize();
	TimeMs t = winSize;
	return t;
}

CompKind Producer::getCompKind() {
	int r = (rand()%100)+1;
	if (r<=paramHandler->getEachPerc()) return EACH_WITHIN;
	else if (r<=paramHandler->getEachPerc()+paramHandler->getFirstPerc()) return FIRST_WITHIN;
	else return LAST_WITHIN;
}






Attribute test::produceIntAttribute(std::string name, int value){
	Attribute attribute;
	attribute.type = INT;
	for (int i=0; i<name.size(); i++){
		attribute.name[i] = name.at(i);
	}
	attribute.name[name.size()]='\0';
	attribute.intVal = value;
	return attribute;
}


Attribute test::produceFloatAttribute(std::string name, float value){
	Attribute attribute;
	attribute.type = FLOAT;
	for (int i=0; i<name.size(); i++){
		attribute.name[i] = name.at(i);
	}
	attribute.name[name.size()]='\0';
	attribute.floatVal = value;
	return attribute;
}


Attribute test::produceBoolAttribute(std::string name, bool value){
	Attribute attribute;
	attribute.type = BOOL;
	for (int i=0; i<name.size(); i++){
		attribute.name[i] = name.at(i);
	}
	attribute.name[name.size()]='\0';
	attribute.boolVal = value;
	return attribute;
}


Attribute test::produceStringAttribute(std::string name, std::string value){
	Attribute attribute;
	attribute.type = STRING;
	for (int i=0; i<name.size(); i++){
		attribute.name[i] = name.at(i);
	}
	attribute.name[name.size()]='\0';
	for (int j=0; j<value.size(); j++){
		attribute.stringVal[j] = value.at(j);
	}
	attribute.stringVal[value.size()]='\0';
	return attribute;
}


Constraint test::produceIntConstraint(std::string name, Op op, int value){
	Constraint constraint;
	constraint.type = INT;
	for (int i=0; i<name.size(); i++){
		constraint.name[i] = name.at(i);
	}
	constraint.name[name.size()]='\0';
	constraint.op = op;
	constraint.intVal = value;
	return constraint;
}


Constraint test::produceFloatConstraint(std::string name, Op op, float value){
	Constraint constraint;
	constraint.type = FLOAT;
	for (int i=0; i<name.size(); i++){
		constraint.name[i] = name.at(i);
	}
	constraint.name[name.size()]='\0';
	constraint.op = op;
	constraint.floatVal = value;
	return constraint;
}


Constraint test::produceBoolConstraint(std::string name, Op op, bool value){
	Constraint constraint;
	constraint.type = BOOL;
	for (int i=0; i<name.size(); i++){
		constraint.name[i] = name.at(i);
	}
	constraint.name[name.size()]='\0';
	constraint.op = op;
	constraint.boolVal = value;
	return constraint;
}


Constraint test::produceStringConstraint(std::string name, Op op, std::string value){
	Constraint constraint;
	constraint.type = STRING;
	for (int i=0; i<name.size(); i++){
		constraint.name[i] = name.at(i);
	}
	constraint.name[name.size()]='\0';
	constraint.op = op;
	for (int j=0; j<value.size(); j++){
		constraint.stringVal[j] = value.at(j);
	}
	constraint.stringVal[value.size()]='\0';
	return constraint;
}

std::string test::toString(PubPkt* pkt){

	stringstream ss;
	ss << "{event=" << pkt->getEventType() << ", attributes={";
	int attrNum= pkt->getAttributesNum();
	for (int i=0; i<= attrNum-1; i++){
		ss << toString(pkt->getAttribute(i));
		if (i<attrNum-1) ss << ", ";
		else ss << "}}";
	}
	return ss.str();
}


std::string test::toString(BackSubPkt* pkt){

	stringstream ss;
	ss << "{event=" << pkt->getEventType() << ", constraints={";
	int constrNum= pkt->getConstraintsNum();
	for (int i=0; i<= constrNum-1; i++){
		ss << toString(pkt->getConstraint(i));
		if (i<constrNum-1) ss << ", ";
		else ss << "}, ";
	}
	ss << "window=" << pkt->getWindow() << "ms, ";
	ss <<  toString(pkt->getOccurrence()) << "}";
	return ss.str();
}

std::string test::toString(RulePkt* pkt){
	CompositeEventTemplate *templ= pkt->getCompositeEventTemplate();
	stringstream ss;
	ss << "{event=" << templ->getEventType() << ", attributes={";
	int attrNum= templ->getAttributesNum();
	for (int i=0; i<= attrNum-1; i++){
		ss << templ->getAttributeName(i);
		if (i<attrNum-1) ss << ", ";
		else ss << "}}";
	}
	return ss.str();
}


std::string test::toString(const Attribute& attr){
	stringstream ss;
	ss << attr.name << "=";

	switch (attr.type){
	case INT:
		ss << attr.intVal;
		break;
	case FLOAT:
		ss << attr.floatVal;
		break;
	case BOOL:
		ss << attr.boolVal;
		break;
	case STRING:
		ss << '"' << attr.stringVal << '"';
		break;
	}

	return ss.str();
}

std::string test::toString(const Constraint& constr){
	stringstream ss;
	ss << constr.name;

	switch (constr.op) {
	case EQ:
		ss << "=";
		break;
	case LT:
		ss << "<";
		break;
	case GT:
		ss << ">";
		break;
	case DF:
		ss << "!=";
		break;
	case IN:
		// set-membership ASCII symbol for Event-B language is used here for substrings
		// see http://wiki.event-b.org/index.php/ASCII_Representations_of_the_Mathematical_Symbols_%28Rodin_User_Manual%29
		ss << ":";
		break;
	}

	switch (constr.type){
	case INT:
		ss << constr.intVal;
		break;
	case FLOAT:
		ss << constr.floatVal;
		break;
	case BOOL:
		ss << constr.boolVal;
		break;
	case STRING:
		ss << '"' << constr.stringVal << '"';
		break;
	}
	return ss.str();
}


std::string test::toString(OccurrenceType occurrence){
	stringstream ss;
	ss << "occurrence=";

	switch (occurrence){
	case ANY:
		ss << "ANY";
		break;
	case LAST:
		ss << "LAST";
		break;
	}

	return ss.str();
}
